package org.dicr.sys;

import java.io.*;
import java.lang.ref.*;
import java.util.*;

/**
 * System file handler. This is handler of system (configuration) files to make
 * singele instances and processing locks.
 * 
 * @author Igor A Tarasov &lt;java@dicr.org&gt;
 * @version 1.0
 */
public class SystemFileHandler {

	/** Handlers */
	private static final Map<String, SoftReference<SystemFileHandler>> handlers = new HashMap<>();

	/** File pathname */
	private String fileName = null;

	/**
	 * Constructor
	 * 
	 * @param the_fileName
	 *            file pathname
	 * @throws FileLockedException
	 *             if file is already locked by other instances
	 */
	public SystemFileHandler(String the_fileName) throws FileLockedException {
		super();
		this.fileName = registerHandler(the_fileName, this);
	}

	/**
	 * Return handler for given file.
	 * 
	 * @param fileName
	 *            file pathname
	 * @return current handler or null if not handled jet.
	 */
	public static synchronized SystemFileHandler getHandler(String fileName) {
		if (fileName == null) {
			throw new IllegalArgumentException("null fileName");
		}
		String absName = new File(fileName).getAbsolutePath();
		SoftReference<SystemFileHandler> ref = handlers.get(absName);
		return ref != null ? ref.get() : null;
	}

	/**
	 * Register handler for system file.
	 * 
	 * @param fileName
	 *            file pathname
	 * @param handler
	 *            handler to register
	 * @return absolute pathname of file
	 * @throws FileLockedException
	 *             if already locked by other handler
	 */
	private static synchronized String registerHandler(String fileName, SystemFileHandler handler)
			throws FileLockedException {
		if (fileName == null) {
			throw new IllegalArgumentException("null fileName");
		}
		if (handler == null) {
			throw new IllegalArgumentException("null handler");
		}
		String absName = new File(fileName).getAbsolutePath();
		SystemFileHandler oldhandler = getHandler(absName);
		if (oldhandler != null) {
			throw new FileLockedException(absName);
		}
		handlers.put(absName, new SoftReference<>(handler));
		return absName;
	}

	/**
	 * Return file name of this handler
	 * 
	 * @return file pathname which this handler lock
	 */
	public String getFileName() {
		return this.fileName;
	}
}
